<?php

require_once dirname(__FILE__) . '/../../bootstrap.unit.php';

class ForageDocumentTest extends PHPUnit_Framework_TestCase
{
  private $document;

  public function setUp()
  {
    $this->document = new ForageDocument();
  }

  public function tearDown()
  {
    unset($this->document);
  }
  
  public function testAppendingTermsWithAdd()
  {
    $field1 = new ForageField('name', 'value');
    $field2 = new ForageField('name', 'value2');

    $this->document->add($field1);
    $this->document->add($field2);

    $this->assertSame($field1, $this->document['name'][0]);
    $this->assertSame($field2, $this->document['name'][1]);
  }

  public function testAppendingBasicTermsWithAdd()
  {
    $this->document->add('name', 'value');
    $this->document->add('name', 'value2');

    $this->assertEquals('value',  $this->document['name'][0]->value);
    $this->assertEquals('value2', $this->document['name'][1]->value);
  }

  public function testUsingFluidInterfaceForAdding()
  {
    $this->document->add('name', 'value')
                   ->add('title', 'title');
    $this->assertEquals(2, count($this->document));
  }

  public function testSettingFieldAttributesWithAdd()
  {
    $this->document->add('name', 'value', array('stored'=>false));
    $this->assertTrue(isset($this->document['name']->properties['stored']));
    $this->assertFalse($this->document['name']->properties['stored']);
  }

  public function testAccessingASingleTerm()
  {
    $field = new ForageField('name', 'value');
    $this->document->add($field);

    $this->assertSame($field, $this->document['name']);
  }

  public function testRemovingASpecificField()
  {
    $field1 = new ForageField('name', 'value');
    $field2 = new ForageField('name', 'value2');

    $this->document[] = $field1;
    $this->document[] = $field2;

    $this->document->remove($field1);

    $this->assertEquals(1, count($this->document['name']));
    $this->assertSame($field2, $this->document['name']);
  }

  public function testCheckingIfDocumentHasAField()
  {
    $field1 = new ForageField('name', 'value');
    $this->assertFalse($this->document->has($field1), "Document should not have field before it's been added.");

    $this->document[] = $field1;
    $this->assertTrue($this->document->has($field1), "Document should have field after it's been added.");
  }

  public function testGettingFieldsWithMagicGet()
  {
    $field1 = new ForageField('name', 'value');
    $field2 = new ForageField('name', 'value2');
    $field3 = new ForageField('other', 'value');

    $this->document->add($field1);
    $this->document->add($field2);
    $this->document->add($field3);

    $this->assertEquals($this->document->fields[0], $field1);
    $this->assertEquals($this->document->fields[1], $field2);
    $this->assertEquals($this->document->fields[2], $field3);
  }

  /* Array Access Tests */
  public function testAppendingTermsWithArrayAccess()
  {
    $field1 = new ForageField('name', 'value');
    $field2 = new ForageField('name', 'value2');

    $this->document[] = $field1;
    $this->document[] = $field2;

    $this->assertSame($field1, $this->document['name'][0], 'Appended field should be available through array access.');
    $this->assertSame($field2, $this->document['name'][1], 'Appended field should be available through array access.');
  }

  public function testRemovingAllTermsForANameWithArrayAccess()
  {
    $field1 = new ForageField('name', 'value');
    $field2 = new ForageField('name', 'value2');

    $this->document[] = $field1;
    $this->document[] = $field2;

    unset($this->document['name']);

    $this->assertEquals(0, count($this->document['name']));
  }

  public function testArrayAccessKeyExists()
  {
    $this->assertFalse(isset($this->document['name']), 'Name should not exist before it is set.');
    $field = new ForageField('name', 'value');
    $this->document[] = $field;
    $this->assertTrue(isset($this->document['name']), 'Name should exist after it has been set.');
  }

  /**
   * @expectedException InvalidArgumentException
   */
  public function testSettingTermToSpecificKeyFails()
  {
    $field = new ForageField('name', 'value');
    $this->document['name'] = $field;
  }

  /**
   * @expectedException InvalidArgumentException
   */
  public function testSettingNonTermFails()
  {
    $field = 'blah';
    $this->document[] = $field;
  }

  /** Countable Tests **/
  public function testEmptyDocumentHasZeroCount()
  {
    $this->assertEquals(0, count($this->document), 'Empty document should have zero count.');
  }

  public function testCountingDocumentWithOneField()
  {
    $this->document[] = new ForageField('name', 'value');
    $this->assertEquals(1, count($this->document), 'Document should have a count of one.');
  }

  public function testCountingDocumentWithTwoFieldsOneName()
  {
    $this->document[] = new ForageField('name', 'value1');
    $this->document[] = new ForageField('name', 'value2');
    $this->assertEquals(2, count($this->document), 'Document should have a count of two.');
  }

  /**
   * @expectedException InvalidArgumentException
   */
  public function testInvalidPropertyAccessThrowsException()
  {
    $this->document->blah;
  }

  public function testSettingProperty()
  {
    $this->assertEquals(array(), $this->document->properties, 'Document should start with no settings.');
    $this->document->setProperty('test', 'value');
    $this->assertEquals(array('test'=>'value'), $this->document->properties, 'Setting property should reflect in access.');
    $this->assertEquals($this->document->getProperty('test'), 'value', 'Property should be accessible from getProperty().');
  }

  public function testGettingFieldsByProperty()
  {
    $field1 = new ForageField('foo', 'bar');
    $field1->setProperty('uid', true);
    $this->document[] = $field1;
    $field2 = new ForageField('bar', 'foo');
    $this->document[] = $field2;

    $fields = $this->document->getFieldsByProperty('uid', true);
    $this->assertEquals(1, count($fields));
    $this->assertSame($field1, $fields[0]);
  }
}
